/*
享元模式：
要点：
1)面向对象很好地解决了抽象性的问题，但是作为一个运行在机器中的程序实体，我们需要考虑对象的代价问题。
Flyweight设计模式主要解决面向对象的代价问题，一般不触及面向对象的抽象性问题。
2)Flyweight采用对象共享的做法来降低系统中对象的个数，从而降低细粒度对象给系统带来的内存压力。在具体实现方面，
要注意对象状态的处理。
3)如果发现这些细粒度的类实例除了几个参数外基本相同，可以把这几个参数移出到类外面，在方法调用时把它传进来，
这样可以大幅度减少单个实例的数量。即区分内部状态和外部状态。
*/ 
// 享元模式 -------------

class Uploader {
  constructor(type, filePath) {
    this.type = type
    this.state = filePath ? "选择文件:" + filePath : "未选择文件"
    this.filePath = filePath
    console.log(this.state)
  }

  selectFile(filePath) {
    this.filePath = filePath
    this.state = "选择文件:" + filePath
    console.log(this.state)
  }

  upload() {
    this.state = "上传中:" + this.filePath
    console.log(this.state)
    return new Promise((resolve) => {
      setTimeout(() => {
        this.state = "上传完成:" + this.filePath
        console.log(this.state)
        resolve()
      }, 1000)
    })
  }
}

class FlashUploader extends Uploader {
  constructor(filePath) {
    super("Flash", filePath)
    this.flashParams = []
  }
}

class HtmlUploader extends Uploader {
  constructor(filePath) {
    super("Html", filePath)
    this.htmlParams = []
  }
}

// 未采用享元模式的代码
const uploaders = [
  new FlashUploader("文件1"),
  new FlashUploader("文件2"),
  new FlashUploader("文件3"),
  new HtmlUploader("文件4"),
  new HtmlUploader("文件5"),
  new HtmlUploader("文件6")
]

function upload(uploaders) {
  let uploader = uploaders.pop()
  uploader.upload().then(() => {
    if (uploaders.length) {
      upload(uploaders)
    }
  })
}
upload(uploaders)

// 采用享元模式
const uploaderFactory = (function () {
  let uploaders = []
  return function uploaderFactory(type, filePath) {
    let uploader = uploaders.find(u => u.type === type)
    if (!uploader) {
      uploader = type === "Html" ? new HtmlUploader() : new FlashUploader()
      uploaders.push(uploader)
    }
    uploader.selectFile(filePath)
    console.log(uploaders, '=================')
    return uploader
  }
})()
uploaderFactory('Flash', "文件1").upload()
  .then(() => uploaderFactory('Flash', "文件2")).upload()
  .then(() => uploaderFactory('Flash', "文件3")).upload()
  .then(() => uploaderFactory('Flash', "文件4")).upload()
  .then(() => uploaderFactory('Html', "文件5")).upload()
  .then(() => uploaderFactory('Html', "文件6")).upload()